#include "modelviewer.h"
#include "ui_modelviewer.h"
#include <cmath>

ModelViewer::ModelViewer(QWidget*parent) :
    QOpenGLWidget(parent),
    ui(new Ui::ModelViewer),
    _vao(0),
    _vbo(0),
    _ibo(0)
{
    ui->setupUi(this);
}

ModelViewer::~ModelViewer()
{
    delete ui;
}

void ModelViewer::initializeGL()
{
    bool succ = initializeOpenGLFunctions();
    if (!succ) {
        qDebug() << "init OpenGL functions failed";
    }
    
    succ = _shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,
        "#version 430\n"
        "layout(location = 0) in vec3 Position;\n"
        "uniform mat4 gWVP;\n"
        "void main()\n"
        "{\n"
        "   gl_Position = gWVP*vec4(Position, 1.0f);\n"
        "}\n"
    );
    if (!succ) {
        qDebug() << "add vertex shader failed: " << _shaderProgram.log();
    }

    succ = _shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,
        "#version 430\n"
        "uniform vec3 gColor;\n"
        "out vec4 FragColor;\n"
        "void main()\n"
        "{\n"
        "   FragColor = vec4(gColor, 1.0f);\n"
        "}\n"
    );
    if (!succ) {
        qDebug() << "add fragment shader failed: " << _shaderProgram.log();
    }

    succ = _shaderProgram.link();
    if (!succ) {
        qDebug() << "link shader program failed: " << _shaderProgram.log();
    }

    float wvp[4][4] = {
        1.0f,0.0f,0.0f,0.0f,
        0.0f,1.0f,0.0f,0.0f,
        0.0f,0.0f,1.0f,0.0f,
        0.0f,0.0f,0.0f,1.0f
    };
    succ = _shaderProgram.bind();
    if (!succ) {
        qDebug() << "bind shader program failed: " << _shaderProgram.log();
    }
    _shaderProgram.setUniformValue("gWVP", wvp);
    GLenum error = glGetError();
    if (error != GL_NO_ERROR) {
        qDebug() << "set gWVP failed: " << error << endl;
    }
    _shaderProgram.setUniformValue("gColor", 1.0f, 1.0f, 0.0f);
    error = glGetError();
    if (error != GL_NO_ERROR) {
        qDebug() << "set gColor failed: " << error << endl;
    }

    GLfloat vertices[12] = {
        0.0f,0.0f,0.0f,
        1.0f,0.0f,0.0f,
        0.5f,0.5f * std::sqrt(3.0f),0.0f,
        0.5f,1.0f / 2.0f / std::sqrt(3.0f),std::sqrt(2.0f / 3.0f)
    };

	unsigned int faces[12] = {
		0, 1, 2,
		0, 3, 1,
		0, 2, 3,
		1, 3, 2
	};

    glGenVertexArrays(1, &_vao);
    glBindVertexArray(_vao);

    glGenBuffers(1, &_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, _vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 12, vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);

    glGenBuffers(1, &_ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 12, faces, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    glBindVertexArray(0);
}

void ModelViewer::paintGL()
{
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBindVertexArray(_vao);
    _shaderProgram.bind();
    glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, 0);
    GLenum error = glGetError();
    if (error != GL_NO_ERROR) {
        qDebug() << "draw call failed" << endl;
    }
    _shaderProgram.release();
    glBindVertexArray(0);
}

void ModelViewer::resizeGL(int w, int h)
{
    if (w < h) {
        int st = (h - w) / 2;
        glViewport(0, st, w, w);
    }
    else {
        int st = (w - h) / 2;
        glViewport(st, 0, h, h);
    }
}

void ModelViewer::mousePressEvent(QMouseEvent* event)
{

}

void ModelViewer::mouseReleaseEvent(QMouseEvent* event)
{

}

void ModelViewer::mouseMoveEvent(QMouseEvent* event)
{

}

void ModelViewer::wheelEvent(QWheelEvent* event)
{

}
